package json

import (
	"encoding/json"
	"errors"
	"fmt"
	"go.uber.org/zap"
	"gogogo-server/engine/cororpc"
	"gogogo-server/engine/network/codec"
	"reflect"
)

// Processor json编码解码
type Processor struct {
	codec.BaseProcessor
}

func NewProcessor() *Processor {
	return &Processor{
		BaseProcessor: codec.BaseProcessor{
			MsgInfos: make(map[any]*codec.MsgInfo),
		},
	}
}

// RegisterRouter 注册为转发
func (p *Processor) RegisterRouter(args ...any) {
	if len(args) < 2 {
		return
	}
	corpc, ok := args[1].(*cororpc.RPCServer)
	if !ok {
		return
	}
	if t, ok := args[0].(string); ok {
		p.MsgInfos[t] = &codec.MsgInfo{
			MsgCoroRPCServer: corpc,
		}
		return
	}
	var msgType = reflect.TypeOf(args[0])
	if nil == msgType || msgType.Kind() != reflect.Pointer {
		zap.S().Fatalf("注册失败,消息:%T 非法", msgType)
	}
	var msgId = msgType.Elem().Name()
	if len(msgId) < 1 {
		zap.S().Fatalf("非法的消息id:%T", args[0])
	}
	if _, ok := p.MsgInfos[msgId]; ok {
		zap.S().Fatalf("重复注册的消息:%T", args[0])
	}
	p.MsgInfos[msgId] = &codec.MsgInfo{
		MsgType:          msgType,
		MsgCoroRPCServer: corpc,
	}
}

func (p *Processor) Route(arg cororpc.IMessageArg) error {
	mi, ok := p.MsgInfos[arg.GetMsgId()]
	if !ok {
		return errors.New(fmt.Sprintf("消息:%s 未注册", arg.GetMsgId()))
	}
	if mi.MsgCoroRPCServer != nil {
		mi.MsgCoroRPCServer.PushPTC(arg)
	}
	return nil
}

func (p *Processor) Unmarshal(data []byte) (cororpc.IMessageArg, error) {
	var m map[string]json.RawMessage
	if err := json.Unmarshal(data, &m); err != nil {
		return nil, err
	}
	for msgId, msgBody := range m {
		mi, ok := p.MsgInfos[msgId]
		if !ok {
			return nil, errors.New(fmt.Sprintf("消息：%s 未注册", msgId))
		}
		msg := reflect.New(mi.MsgType.Elem()).Interface()
		return &cororpc.BaseMessageArg{
			MsgId: mi.MsgType,
			Msg:   msg,
		}, json.Unmarshal(msgBody, msg)
	}
	return nil, errors.New("unknown Protocol")
}

func (p *Processor) Marshal(arg cororpc.IMessageArg) ([][]byte, error) {
	msgId := arg.GetMsgId().(reflect.Type).Elem().Name()
	m := map[string]any{msgId: arg.GetMsg()}
	b, e := json.Marshal(m)
	return [][]byte{b}, e
}
